home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Panorama
/
Panorama - Disk 01 (1986-02-15)(Pacific North-West Amigas Club)[WB].zip
/
Panorama - Disk 01 (1986-02-15)(Pacific North-West Amigas Club)[WB].adf
/
aterm5.c
< prev
next >
Wrap
Text File
|
1985-11-26
|
42KB
|
1,379 lines
/************************************************************************
* a terminal program that has ascii and xmodem transfer capability
*
* use esc to abort xmodem transfer
*
* written by Michael Mounier
*
* Modification History -
* December 85 - added 80 * 25 capabilities - Larry Phillips
* Feb 9 1986 - added Half-duplex and Echoplex
* - added timing to and fixed bugs in XMODEM receive
* - fixed bug in Ascii send -- now doesn't wait for EVENT
* to send next characters - Steve Allen
************************************************************************/
#define TESTING 1
/* compiler directives to fetch the necessary header files */
#include <exec/types.h>
#include <exec/exec.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/text.h>
#include <graphics/regions.h>
#include <graphics/copper.h>
#include <graphics/gels.h>
#include <devices/serial.h>
#include <devices/keymap.h>
#include <hardware/blit.h>
#include <stdio.h>
#include <ctype.h>
#include <libraries/dos.h>
#define INTUITION_REV 1
#define GRAPHICS_REV 1
/* things for xmodem send and receive */
#define SECSIZ 128 /* This many bytes in an xmodem block */
#define BufSize SECSIZ*2 /* We'll follow two blocks (for chop) */
#define ERRORMAX 10 /* Max errors before abort */
#define RETRYMAX 10 /* Maximum retrys before abort */
#define SOH 1 /* Start of sector char */
#define EOT 4 /* end of transmission char */
#define ACK 6 /* acknowledge sector transmission */
#define NAK 21 /* error in transmission detected */
#define CAN 'X'&0x1f
#define CR 13
#define BELL 'G'&0x1f
#define CPM_EOF 'Z'&0x1f /*CP/M end of file character */
static char
bufr[BufSize], numstring[5];
static int
fd,
timeout = FALSE,
cancel,
LOCAL, ECHO;
static long
bytes_xferred;
UBYTE ModemRead(); /* C demands this non-integer declaration */
/* 'cause ModemRead is used before it is defined */
/* Intuition always wants to see these declarations */
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
/* my window structure */
struct NewWindow NewWindow = {
0,
0,
640,
200,
0,
1,
CLOSEWINDOW | RAWKEY | MENUPICK | NEWSIZE,
WINDOWCLOSE | SMART_REFRESH | ACTIVATE | WINDOWDEPTH | REPORTMOUSE
| BORDERLESS,
NULL,
NULL,
"AMIGA Terminal",
NULL,
NULL,
100, 35,
640, 200,
WBENCHSCREEN,
};
struct Window *mywindow; /* ptr to applications window */
struct IntuiMessage *NewMessage; /* msg structure for GetMsg() */
/*****************************************************
* File Menu
*****************************************************/
/* define maximum number of menu items */
#define FILEMAX 4
/* declare storage space for menu items and
* their associated IntuiText structures
*/
struct MenuItem FileItem[FILEMAX];
struct IntuiText FileText[FILEMAX];
/*****************************************************************/
/* The following function initializes the structure arrays */
/* needed to provide the File menu topic. */
/*****************************************************************/
InitFileItems()
{
short n;
/* initialize each menu item and IntuiText with loop */
for( n=0; n<FILEMAX; n++ )
{
FileItem[n].NextItem = &FileItem[n]+1;
FileItem[n].LeftEdge = 0;
FileItem[n].TopEdge = 11 * n;
FileItem[n].Width = 135;
FileItem[n].Height = 11;
FileItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX;
FileItem[n].MutualExclude = 0;
FileItem[n].ItemFill = (APTR)&FileText[n];
FileItem[n].SelectFill = NULL;
FileItem[n].Command = 0;
FileItem[n].SubItem = NULL;
FileItem[n].NextSelect = 0;
FileText[n].FrontPen = 0;
FileText[n].BackPen = 1;
FileText[n].DrawMode = JAM2; /* render in fore and background */
FileText[n].LeftEdge = 0;
FileText[n].TopEdge = 1;
FileText[n].ITextFont = NULL;
FileText[n].NextText = NULL;
}
FileItem[FILEMAX-1].NextItem = NULL;
/* initialize text for specific menu items */
FileText[0].IText = (UBYTE *)"Ascii Capture";
FileText[1].IText = (UBYTE *)"Ascii Send";
FileText[2].IText = (UBYTE *)"Xmodem Receive";
FileText[3].IText = (UBYTE *)"Xmodem Send";
return( 0 );
}
/*****************************************************/
/* BaudRate Menu */
/*****************************************************/
/* define maximum number of menu items */
#define RSMAX 5
/* declare storage space for menu items and
* their associated IntuiText structures
*/
struct MenuItem RSItem[RSMAX];
struct IntuiText RSText[RSMAX];
/*****************************************************************/
/* The following function initializes the structure arrays */
/* needed to provide the BaudRate menu topic. */
/*****************************************************************/
InitRSItems()
{
short n;
/* initialize each menu item and IntuiText with loop */
for( n=0; n<RSMAX; n++ )
{
RSItem[n].NextItem = &RSItem[n]+1;
RSItem[n].LeftEdge = 0;
RSItem[n].TopEdge = 11 * n;
RSItem[n].Width = 85;
RSItem[n].Height = 11;
RSItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT;
RSItem[n].MutualExclude = (~(1 << n));
RSItem[n].ItemFill = (APTR)&RSText[n];
RSItem[n].SelectFill = NULL;
RSItem[n].Command = 0;
RSItem[n].SubItem = NULL;
RSItem[n].NextSelect = 0;
RSText[n].FrontPen = 0;
RSText[n].BackPen = 1;
RSText[n].DrawMode = JAM2; /* render in fore and background */
RSText[n].LeftEdge = 0;
RSText[n].TopEdge = 1;
RSText[n].ITextFont = NULL;
RSText[n].NextText = NULL;
}
RSItem[RSMAX-1].NextItem = NULL;
/* 300 baud item chekced */
RSItem[0].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT | CHECKED;
/* initialize text for specific menu items */
RSText[0].IText = (UBYTE *)" 300";
RSText[1].IText = (UBYTE *)" 1200";
RSText[2].IText = (UBYTE *)" 2400";
RSText[3].IText = (UBYTE *)" 4800";
RSText[4].IText = (UBYTE *)" 9600";
return( 0 );
}
/***************************************************
* Mode menu (feb.86)
****************************************************/
struct MenuItem ModeItem[3];
struct IntuiText Modetext[3];
initmode()
{
short n;
for ( n=0; n<3; n++)
{
ModeItem[n].NextItem = &ModeItem[n]+1; /* Lattice 3.03 likes this syntax */
ModeItem[n].LeftEdge = 0;
ModeItem[n].TopEdge = 11 * n;
ModeItem[n].Width = 50;
ModeItem[n].Height = 11;
ModeItem[n].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT;
ModeItem[n].MutualExclude = (~(1 << n));
ModeItem[n].ItemFill = (APTR) &Modetext[n];
ModeItem[n].SelectFill = NULL;
ModeItem[n].Command = 0;
ModeItem[n].SubItem = NULL;
ModeItem[n].NextSelect = 0;
Modetext[n].FrontPen = 0;
Modetext[n].BackPen = 1;
Modetext[n].DrawMode = JAM2;
Modetext[n].LeftEdge = 0;
Modetext[n].TopEdge = 1;
Modetext[n].ITextFont = NULL;
Modetext[n].NextText = NULL;
}
ModeItem[2].NextItem = NULL;
/* default is Terminal mode (full duplex) */
ModeItem[1].Flags = ITEMTEXT | ITEMENABLED | HIGHBOX | CHECKIT | CHECKED;
LOCAL = 0;
ECHO = 0;
Modetext[0].IText = " Half";
Modetext[1].IText = " Full";
Modetext[2].IText = " Echo";
} /* end initmode */
/***************************************************/
/* Menu Definition */
/* */
/* This section of code is where the simple */
/* menu definition goes. */
/***************************************************/
/* current number of available menu topics */
#define MAXMENU 3
/* declaration of menu structure array for
* number of current topics. Intuition
* will use the address of this array to
* set and clear the menus associated with
* the window.
*/
struct Menu menu[MAXMENU];
/**********************************************************************/
/* The following function initializes the Menu structure array with */
/* appropriate values for our simple menu strip. Review the manual */
/* if you need to know what each value means. */
/**********************************************************************/
InitMenu()
{
menu[0].NextMenu = &menu[1];
menu[0].LeftEdge = 5;
menu[0].TopEdge = 0;
menu[0].Width = 50;
menu[0].Height = 10;
menu[0].Flags = MENUENABLED;
menu[0].MenuName = "File"; /* text for menu-bar display */
menu[0].FirstItem = &FileItem[0]; /* pointer to first item in list */
menu[1].NextMenu = &menu[2];
menu[1].LeftEdge = 65;
menu[1].TopEdge = 0;
menu[1].Width = 85;
menu[1].Height = 10;
menu[1].Flags = MENUENABLED;
menu[1].MenuName = "BaudRate"; /* text for menu-bar display */
menu[1].FirstItem = &RSItem[0]; /* pointer to first item in list */
menu[2].NextMenu = NULL; /* (feb.86) */
menu[2].LeftEdge = 150;
menu[2].TopEdge = 0;
menu[2].Width = 40;
menu[2].Height = 10;
menu[2].Flags = MENUENABLED;
menu[2].MenuName = "Mode";
menu[2].FirstItem = &ModeItem[0];
}
/* declarations for the serial stuff */
extern struct MsgPort *CreatePort();
struct IOExtSer *Read_Request;
static char rs_in[2];
struct IOExtSer *Write_Request;
static char rs_out[2];
/******************************************************/
/* Main Program */
/* */
/* This is the main body of the program. */
/******************************************************/
main()
{
ULONG class;
USHORT code,menunum,itemnum;
int KeepGoing,capture,send;
char c,name[32];
FILE *tranr,*trans;
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", INTUITION_REV);
if( IntuitionBase == NULL )
{
puts("can't open intuition\n");
exit(TRUE);
}
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",GRAPHICS_REV);
if( GfxBase == NULL )
{
puts("can't open graphics library\n");
exit(TRUE);
}
if(( mywindow = (struct Window *)OpenWindow(&NewWindow) ) == NULL)
{
puts("cant open window\n");
exit(TRUE);
}
Read_Request = (struct IOExtSer *)AllocMem(sizeof(*Read_Request),MEMF_PUBLIC|MEMF_CLEAR);
Read_Request->io_SerFlags = SERF_SHARED;
Read_Request->io_CtlChar = 0x11130501;
Read_Request->IOSer.io_Message.mn_ReplyPort = CreatePort("Read_RS",0);
if(OpenDevice(SERIALNAME,NULL,Read_Request,NULL))
{
puts("Cant open Read device\n");
CloseWindow( mywindow );
DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort);
FreeMem(Read_Request,sizeof(*Read_Request));
exit(TRUE);
}
Read_Request->IOSer.io_Command = CMD_READ;
Read_Request->IOSer.io_Length = 1;
Read_Request->IOSer.io_Data = (APTR) &rs_in[0];
Write_Request = (struct IOExtSer *)AllocMem(sizeof(*Write_Request),MEMF_PUBLIC|MEMF_CLEAR);
Write_Request->io_SerFlags = SERF_SHARED;
Write_Request->io_CtlChar = 0x11130501;
Write_Request->IOSer.io_Message.mn_ReplyPort = CreatePort("Write_RS",0);
if(OpenDevice(SERIALNAME,NULL,Write_Request,NULL))
{
puts("Cant open Write device\n");
CloseWindow( mywindow );
DeletePort(Write_Request->IOSer.io_Message.mn_ReplyPort);
FreeMem(Write_Request,sizeof(*Write_Request));
DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort);
FreeMem(Read_Request,sizeof(*Read_Request));
exit(TRUE);
}
Write_Request->IOSer.io_Command = CMD_WRITE;
Write_Request->IOSer.io_Length = 1;
Write_Request->IOSer.io_Data = (APTR) &rs_out[0];
Read_Request->io_SerFlags = SERF_SHARED | SERF_XDISABLED;
Read_Request->io_Baud = 300;
Read_Request->io_ReadLen = 8;
Read_Request->io_WriteLen = 8;
Read_Request->io_CtlChar = 1L;
Read_Request->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO(Read_Request);
Read_Request->IOSer.io_Command = CMD_READ;
InitFileItems();
InitRSItems();
initmode();
InitMenu();
SetMenuStrip(mywindow,&menu[0]);
KeepGoing = TRUE;
capture=FALSE;
send=FALSE;
SetAPen(mywindow->RPort,1);
emit(12);
BeginIO(Read_Request);
while( KeepGoing )
{
/* wait for window message or serial port message */
if (send == 0) /* don't wait for event when sending */
Wait((1 << Read_Request->IOSer.io_Message.mn_ReplyPort->mp_SigBit) | ( 1 << mywindow->UserPort->mp_SigBit));
if (send)
{
if ((c=getc(trans)) != EOF)
{
if (c == '\n') sendchar(CR); /* add carriage return */
sendchar(c);
}
else
{
fclose(trans);
emits("\nFile Sent\n");
send=FALSE;
}
}
if(CheckIO(Read_Request))
{
WaitIO(Read_Request);
c=rs_in[0] & 0x7f;
BeginIO(Read_Request);
emit(c);
if (ECHO) /* simple echo, no LF after CR (feb.86) */
{
rs_out[0] = c; /* must do this way: sendchar() also */
DoIO(Write_Request); /* emit()s if LOCAL, and calling sendchar() */
} /* would do a double-emit() in EchoPlex */
if (capture)
if (c > 31 && c < 127 || c == '\n') /* assumes CR/LF sequence */
/* trash them mangy ctl chars */
putc(c , tranr);
}
while( NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort) )
{
class = NewMessage->Class;
code = NewMessage->Code;
ReplyMsg( NewMessage );
switch( class )
{
case CLOSEWINDOW:
/* User is ready to quit, so indicate
* that execution should terminate
* with next iteration of the loop.
*/
KeepGoing = FALSE;
break;
case RAWKEY:
/* User has touched the keyboard */
switch( code )
{
case 95: /* help key */
emits("ESC Aborts Xmodem Xfer\n");
emits("Front/Back gadgets and Close gadget are still active though usneen.\n");
emits("AMIGA Term 1.0\n");
emits("Copyright 1985 by Michael Mounier\n");
break;
default:
c = toasc(code); /* get in into ascii */
if (c != 0)
{
rs_out[0] = c;
DoIO(Write_Request);
if (LOCAL) emit(c);
}
break;
}
break;
case NEWSIZE:
emit(12);
break;
case MENUPICK:
if ( code != MENUNULL )
{
menunum = MENUNUM( code );
itemnum = ITEMNUM( code );
switch( menunum )
{
case 0:
switch( itemnum )
{
case 0:
if (capture == TRUE)
{
capture=FALSE;
fclose(tranr);
emits("\nEnd File Capture\n");
}
else
{
emits("\nAscii Capture:");
filename(name);
if ((tranr=fopen(name,"w")) == 0)
{
capture=FALSE;
emits("\nError Opening File\n");
break;
}
capture=TRUE;
}
break;
case 1:
if (send == TRUE)
{
send=FALSE;
fclose(trans);
emits("\nFile Send Cancelled\n");
}
else
{
emits("\nAscii Send:");
filename(name);
if ((trans=fopen(name,"r")) == 0)
{
send=FALSE;
emits("\nError Opening File\n");
break;
}
send=TRUE;
}
break;
case 2:
emits("\nXmodem Receive:");
filename(name);
if (XMODEM_Read_File(name))
{
emits("\nReceived File\n");
emit(BELL);
}
else
{
close(fd);
emits("Xmodem Receive Failed\n");
emit(BELL);
}
break;
case 3:
emits("\nXmodem Send:");
filename(name);
if (XMODEM_Send_File(name))
{
emits("\nSent File\n");
emit(BELL);
}
else
{
close(fd);
emits("\nXmodem Send Failed\n");
emit(BELL);
}
break;
}
break;
case 1:
AbortIO(Read_Request);
switch( itemnum )
{
case 0:
Read_Request->io_Baud = 300;
break;
case 1:
Read_Request->io_Baud = 1200;
break;
case 2:
Read_Request->io_Baud = 2400;
break;
case 3:
Read_Request->io_Baud = 4800;
break;
case 4:
Read_Request->io_Baud = 9600;
break;
}
Read_Request->IOSer.io_Command = SDCMD_SETPARAMS;
DoIO(Read_Request);
Read_Request->IOSer.io_Command = CMD_READ;
BeginIO(Read_Request);
break;
case 2: /* "Mode" (feb.86) */
switch( itemnum)
{
case 0: /* Half Duplex */
ECHO = 0;
LOCAL = 1;
break;
case 1: /* Full Duplex */
ECHO = 0;
LOCAL = 0;
break;
case 2: /* EchoPlex */
ECHO = 1;
LOCAL = 1;
}
} /* end of switch ( menunum ) */
} /* end of if ( not null ) */
} /* end of switch (class) */
} /* end of while ( newmessage )*/
} /* end while ( keepgoing ) */
/* It must be time to quit, so we have to clean
* up and exit.
*/
CloseDevice(Read_Request);
DeletePort(Read_Request->IOSer.io_Message.mn_ReplyPort);
FreeMem(Read_Request,sizeof(*Read_Request));
CloseDevice(Write_Request);
DeletePort(Write_Request->IOSer.io_Message.mn_ReplyPort);
FreeMem(Write_Request,sizeof(*Write_Request));
ClearMenuStrip( mywindow );
CloseWindow( mywindow );
exit(FALSE);
} /* end of main */
/*************************************************
* function to get file name
*************************************************/
filename(name)
char name[];
{
char c;
ULONG class;
USHORT code;
int keepgoing,i;
keepgoing = TRUE;
i=0;
while (keepgoing) {
while( NewMessage=(struct IntuiMessage *)GetMsg(mywindow->UserPort) )
{
class = NewMessage->Class;
code = NewMessage->Code;
ReplyMsg( NewMessage );
if (class=RAWKEY)
{
c = toasc(code);
name[i]=c;
if (name[i] != 0)
{
if (name[i] == 13)
{
name[i]=0;
keepgoing = FALSE;
}
else
{
if (name[i] == 8)
{
i -=2;
if (i < -1)
i = -1;
else
{
emit(8);
emit(32);
emit(8);
}
}
else
emit(c);
}
i += 1;
}
}
} /* end of new message loop */
} /* end of god knows what */
emit(13);
} /* end of function */
/*************************************************
* function to print a string
*************************************************/
emits(string)
char string[];
{
int i;
char c;
i=0;
while (string[i] != 0)
{
c=string[i];
if (c == 10)
c = 13;
emit(c);
i += 1;
}
}
sendchar(ch)
int ch;
{
rs_out[0] = ch;
DoIO(Write_Request);
if (LOCAL) emit(ch); /* if Half-Duplex or Echo-plex (feb.86) */
}
/**************************************************************/
/* send char and read char functions for the xmodem function */
/************************************************************/
/* purge() is called whenever an error is detected.
Its function is to flush the input buffer, and wait
until the sender has finished sending a block.
This ensures that the sender will see the NAK
sent by the error routine.
(feb.86)
*/
void purge(purgetime)
int purgetime; /* number of ticks @ 50 per second */
{
do ModemRead(purgetime);
while (timeout == FALSE); /* Wait for the line to clear */
}
/* ModemSend() is simply sendchar() without local echo
(feb.86) */
void ModemSend(c)
UBYTE c;
{ rs_out[0] = c;
DoIO(Write_Request);
}
/* ModemRead() gets a character from the serial port within a
specified number of ticks (tick = 1/50 second). DateStamp()
returns a 3-byte integer date consisting of day, minute, ticks.
ModemRead() will function correctly as long as the date is set
and a day boundary isn't crossed.
(feb.86')
*/
UBYTE ModemRead(MAXTICKS)
int MAXTICKS; /* number of ticks @ 50 per second */
{
static int startime[3], endtime[3];
UBYTE c;
timeout = FALSE;
DateStamp(startime);
do {
if (NewMessage = (struct IntuiMessage *)GetMsg(mywindow->UserPort))
{
if (NewMessage->Class == RAWKEY) /* test for user cancelling */
{
if ((NewMessage->Code) == 69) /* escape key pressed */
{ cancel = TRUE;
return (0); /* This will tend to force an error */
} /* when <esc> pressed 'midst block receive */
}
}
if (CheckIO(Read_Request))
{ WaitIO(Read_Request);
c = rs_in[0];
BeginIO(Read_Request);
return c; /* Character came in on time */
}
DateStamp(endtime);
endtime[2] -= startime[2];
if ( endtime[1] -= startime[1] ) /* did minutes count change? */
endtime[2] += endtime[1] * 3000; /* number of ticks in minute */
}
while (endtime[2] < MAXTICKS);
/* else character not received on time */
timeout = TRUE;
return (0);
}
/* CloseEmUp() closes a receive file, ending Xmodem receive.
It also performs a 'chop' function, testing for
zero, 0xff, and CP/M_EOF (ctrol-z).
To implement the chop function, a two-block buffer
is maintained, with the basic pointer being bufr[offset],
with offset toggled 0,SECSIZ,0, etc.
During file receive, writes lag reads by one block: e.g.,
when block # 3 is received, block # 2 is written.
If block # 3 is the final block, CloseEmUp() will
chop any invalid characters, write the block, and
close the file. (feb.86)
*/
CloseEmUp(fd,bufr,offset,ourblock)
int offset, ourblock;
UBYTE *bufr;
{
int i;
UBYTE c;
offset = offset ? 0 : SECSIZ ; /* toggle offset */
if (ourblock) /* skip if no data at all */
{
i = SECSIZ - 1;
c = bufr[offset + i]; /* c gets last char in block */
if ( (c == 0) || (c == CPM_EOF) || (c == 0xff) )
{
while (bufr[ offset+(--i) ] == c) /* Chop those useless bytes! */
;
}
if ((c = write(fd, bufr+offset, ++i)) != i)
emits("Error writing final block\n");
stcu_d(numstring, SECSIZ-i, 4);
emits(numstring);
emits(" bytes chopped from final block\n");
}
close(fd);
}
/**************************************/
/* xmodem send and receive functions */
/************************************/
/* These time constants are for benifit of
CompuServe and other packet-switching networks
that must be allowed more "slack time"
due to inherent delays in system.
*/
#define Blocktime 20*50 /* Wait 20 seconds for start of block */
#define Chartime 2*50 /* Wait 2 seconds for chars when getting block */
XMODEM_Read_File(file) /* (feb.86) */
char *file;
{
extern int timeout;
int blockin, ourblock, errors, checksum, offset, x,i; /*NEWCODE*/
unsigned char c;
if ( (fd = creat(file,0)) < 0)
{ emits("Cannot open file\n");
return FALSE;
}
else emits("Receiving file \n");
/* Input file now open */
offset = ourblock = errors = cancel = 0;
ModemSend(NAK);
/* MAIN LOOP STARTS HERE */
loop:
c = ModemRead(Blocktime);
if (cancel)
{ emits("Xmodem cancelled\n");
close(fd);
purge(Chartime);
ModemSend(CAN);
return(FALSE);
}
if (timeout)
{ emits("timed out waiting for block start\n");
goto error;
}
switch (c)
{
case (CAN): /*Sender just quit*/
{ purge(Chartime);
emits("Sender aborted transfer\n");
CloseEmUp(fd,bufr,offset,ourblock);
return(FALSE);
}
case (EOT): /*Sender is finished */
{
CloseEmUp(fd,bufr,offset,ourblock); /* chop and write last block */
emits("Transfer Completed\n");
ModemSend(ACK);
return(TRUE);
}
case (! SOH):
{ purge(Chartime);
emits("not a valid header\n");
goto error;
}
default: /*Sender has a block for us */
break; /* block receive follows here */
}
blockin = ModemRead(Chartime); /* get block number */
if (timeout)
{ purge(Chartime);
emits("Didn't get block# in time\n");
goto error;
}
c = ModemRead(Chartime); /* get 1/blocknumber */
if (timeout)
{ purge(Chartime);
emits("Timed out waiting for 1/block#\n");
goto error;
}
if ((c + blockin) != 255) /* block # got lunched */
{ purge(Chartime);
emits("block complement didn't match\n");
goto error;
}
/* Here comes a block of data */
checksum = 0;
for (i = 0; i < SECSIZ; i++ )
{
c = ModemRead(Chartime);
if (timeout)
{ purge(Chartime);
emits("Timed out during block\n");
goto error;
}
bufr[offset+i] = c;
checksum += c;
}
/* Here comes the checksum */
c = ModemRead(Chartime);
if (timeout)
{ purge(Chartime);
emits("Timed out waiting for checksum\n");
goto error;
}
if (c != (checksum & 0xff) ) /* checksums don't match */
{
purge(Chartime);
emits("checksum error\n");
goto error;
}
/* Block has been received OK: Now check back on blocknumber */
switch ( (char) (blockin - (ourblock & 0xff)) )
{
case (0): /* Duplicate block */
{
emits("\nDuplicate block # ");
stcu_d(numstring,ourblock,4);
emits(numstring);
emit( '\r' );
errors = 0;
ModemSend(ACK);
goto loop;
}
case (1): /* New block */
{
ourblock++; /* Update our block count */
emits("\vReceived block # ");
stcu_d(numstring,ourblock,4);
emits(numstring);
emits(" \n" );
offset = offset ? 0 : SECSIZ; /* toggle offset */
if (ourblock != 1)
{ /* Write it out */
if ( (x = (write(fd, bufr+offset, SECSIZ)) ) != SECSIZ)
{ close(fd);
emits("Error writing to file.\n");
emits("Transfer aborted.\n");
ModemSend(CAN);
return(FALSE);
}
}
errors = 0;
ModemSend(ACK);
goto loop;
}
default:
break; /* fall through to error: */
}
purge(Chartime);
emits("Block numbers didn't agree\n");
/* ERROR ROUTINE STARTS HERE */
error:
if (cancel)
{ emits("XModem cancelled\n");
close(fd);
ModemSend(CAN);
return(FALSE);
}
errors++;
if (errors == 10) /* then abort */
{
emits(" 10 Errors. Transfer cancelled.\n");
close(fd);
ModemSend(CAN);
return(FALSE);
}
emits("Error # ");
emit( errors + '0');
emit( '\r' );
ModemSend(NAK);
goto loop;
} /* end of XMODEM_Read_File() */
#define WaitTime 20*50 /* Wait this long for NAKs (20 seconds)*/
XMODEM_Send_File(file)
char *file;
{
int sectnum, bytes_to_send, size, attempts, c, i;
unsigned checksum, j, bufptr;
char numb[10];
timeout=FALSE;
bytes_xferred = 0;
if ((fd = open(file, 1)) < 0)
{
emits("Cannot Open Send File\n");
return FALSE;
}
else
emits("Sending File\n");
attempts = 0;
sectnum = 1;
/* wait for sync char */
j=1;
while (((c = ModemRead()) != NAK) && (j++ < ERRORMAX));
if (j >= (ERRORMAX))
{
emits("\nReceiver not sending NAKs\n");
return FALSE;
};
while ((bytes_to_send = read(fd, bufr, BufSize)) && attempts != RETRYMAX)
{
if (bytes_to_send == EOF)
{
emits("\nError Reading File\n");
return FALSE;
};
bufptr = 0;
while (bytes_to_send > 0 && attempts != RETRYMAX)
{
attempts = 0;
do
{
ModemSend(SOH);
ModemSend(sectnum);
ModemSend(~sectnum);
checksum = 0;
size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send;
bytes_to_send -= size;
for (j = bufptr; j < (bufptr + SECSIZ); j++)
if (j < (bufptr + size))
{
ModemSend(bufr[j]);
checksum += bufr[j];
}
else
{
ModemSend(0);
}
ModemSend(checksum & 0xff);
attempts++;
c = ModemRead(WaitTime);
if (timeout == TRUE)
return FALSE;
}
while ((c != ACK) && (attempts != RETRYMAX));
bufptr += size;
bytes_xferred += size;
emits("Block ");
stci_d(numb,sectnum,i);
emits(numb);
emits(" sent\n");
sectnum++;
}
}
close(fd);
if (attempts == RETRYMAX)
{
emits("\nNo Acknowledgment Of Sector, Aborting\n");
return FALSE;
}
else
{
attempts = 0;
do
{
ModemSend(EOT);
attempts++;
}
while ((ModemRead(WaitTime) != ACK) && (attempts != RETRYMAX) && (timeout == FALSE));
if (attempts == RETRYMAX)
emits("\nNo Acknowledgment Of End Of File\n");
};
return TRUE;
}
/*************************************************
* function to output ascii chars to window
*************************************************/
emit(c)
char c;
{
static short x = 0;
static short y = 0;
short xmax,ymax,cx,cy;
xmax = mywindow->Width;
ymax = mywindow->Height;
/* cursor */
if (c != 0)
{
if (x > (xmax-3))
{
cx = 7;
cy = y + 8;
}
else
{
cx = x+8;
cy = y;
}
if (cy > (ymax-2))
{
cx = 7;
cy -= 8;
}
SetDrMd(mywindow->RPort,COMPLEMENT);
SetAPen(mywindow->RPort,3);
RectFill(mywindow->RPort,cx-7,cy-6,cx,cy+1);
SetAPen(mywindow->RPort,1);
SetDrMd(mywindow->RPort,JAM2);
if (x > (xmax-3))
{
x = 0;
y += 8;
}
if (y > (ymax-2))
{
x = 0;
y -= 8;
}
Move(mywindow->RPort,x,y);
switch( c )
{
case '\t':
x += 40;
break;
case '\n':
break;
case CR: /* carriage return */
x = 0;
y += 8;
break;
case 8: /* backspace */
x -= 8;
if (x < 1)
x = 0;
break;
case '\v': /* vertical tab */
y -=8;
if ( y<14 )
y = 6;
break;
case 12: /* page */
x = 0;
y = 6;
SetAPen(mywindow->RPort,0);
RectFill(mywindow->RPort,0,0,xmax,ymax);
SetAPen(mywindow->RPort,1);
break;
case BELL: /* bell */
ClipBlit(mywindow->RPort,0,0,mywindow->RPort,0,0,xmax,ymax,0x50);
ClipBlit(mywindow->RPort,0,0,mywindow->RPort,0,0,xmax,ymax,0x50);
break;
default:
Text(mywindow->RPort,&c,1);
x += 8;
} /* end of switch */
/* cursor */
if (x > (xmax-3))
{
cx = 7;
cy = y + 8;
}
else
{
cx = x+8;
cy = y;
}
if (cy > (ymax-2))
{
cx = 7;
cy -= 8;
ScrollRaster(mywindow->RPort,0,8,0,0,xmax,ymax);
}
SetAPen(mywindow->RPort,3);
RectFill(mywindow->RPort,cx-7,cy-6,cx,cy+1);
SetAPen(mywindow->RPort,1);
}
} /* end if (c !=0) */
/*************************************************
* function to take raw key data and convert it
* into ascii chars
**************************************************/
toasc(code)
USHORT code;
{
static int ctrl = FALSE;
static int shift = FALSE;
static int capsl = FALSE;
char c;
static char keys[75] = { /* 'return' and 'enter' generate chr$(13) */
'`','1','2','3','4','5','6','7','8','9','0','-' /* 0x0b */,
'=','\\',0,'0','q','w','e','r','t','y','u','i','o', /* 0x18 */
'p','[',']',0,'1','2','3','a','s','d','f','g','h', /* 0x25 */
'j','k','l',';','\'',0,0,'4','5','6', 0,'z','x','c','v', /* 0x34 */
'b','n','m',44,'.','/',0,'.' ,'7','8','9',' ',8, /* 0x41 */
'\t',13,13,27,127,0,0,0,'-' } ;
/* del */
switch ( code ) /* I didn't know about the Qualifier field when I wrote this */
{
case 98:
capsl = TRUE;
c = 0;
break;
case 226:
capsl = FALSE;
c = 0;
break;
case 99:
ctrl = TRUE;
c = 0;
break;
case 227:
ctrl = FALSE;
c = 0;
break;
case 96:
case 97:
shift = TRUE;
c = 0;
break;
case 224:
case 225:
shift = FALSE;
c = 0;
break;
default:
if (code < 75)
c = keys[code];
else
c = 0;
}
/* add modifiers to the keys */
if (c != 0)
{
if (ctrl && (c <= 'z') && (c >= 'a'))
c -= 96;
else if (shift)
{
if ((c <= 'z') && (c >= 'a'))
c -= 32;
else
switch( c )
{
case '[':
c = '{';
break;
case ']':
c = '}';
break;
case '\\':
c = '|';
break;
case '\'':
c = '"';
break;
case ';':
c = ':';
break;
case '/':
c = '?';
break;
case '.':
c = '>';
break;
case ',':
c = '<';
break;
case '`':
c = '~';
break;
case '=':
c = '+';
break;
case '-':
c = '_';
break;
case '1':
c = '!';
break;
case '2':
c = '@';
break;
case '3':
c = '#';
break;
case '4':
c = '$';
break;
case '5':
c = '%';
break;
case '6':
c = '^';
break;
case '7':
c = '&';
break;
case '8':
c = '*';
break;
case '9':
c = '(';
break;
case '0':
c = ')';
break;
default:
} /* end switch */
} /* end shift */
else if (capsl && (c <= 'z') && (c >= 'a'))
c -= 32;
} /* end modifiers */
return(c);
} /* end of routine */
/* end of file */